package com.turman.common.net.config

import android.util.Log
import okhttp3.*
import java.lang.StringBuilder
import java.net.URLDecoder
import java.text.SimpleDateFormat
import java.util.*

/**
 * 网络日志过滤器
 */
class KtHttpLogInterceptor(block:(KtHttpLogInterceptor.()->Unit)?=null):Interceptor {
    private var logLevel:LogLevel = LogLevel.NONE
    private var colorLevel:ColorLevel = ColorLevel.DEBUG
    private var logTag:String = TAG

    init {
        block?.invoke(this)
    }

    fun logLevel(level:LogLevel):KtHttpLogInterceptor {
        logLevel = level
        return this
    }

    fun colorLevel(level:ColorLevel):KtHttpLogInterceptor {
        colorLevel = level
        return this
    }

    fun logTag(tag:String):KtHttpLogInterceptor {
        logTag = tag
        return this
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        val request:Request = chain.request()
        return kotlin.runCatching { chain.proceed(request) }
            .onFailure {
                it.printStackTrace()

            }
            .onSuccess {
                if (logLevel == LogLevel.NONE) {
                    return it
                }
                logRequest(request,chain.connection())
                logResponse(it)
            }
            .getOrThrow()
    }

    private fun logRequest(request: Request,connection:Connection?) {
        val sb = StringBuilder()
        sb.append("\r\n")
        sb.appendLine("->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->")
        when(logLevel) {
            LogLevel.NONE->{}
            LogLevel.BASIC->{
                logBasicReq(sb,request,connection)
            }
            LogLevel.HEADERS->{
                logHeadersReq(sb,request,connection)
            }
            LogLevel.BODY->{
                logBodyReq(sb,request,connection)
            }
        }
        sb.appendLine("->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->")
        logIt(sb)
    }

    private fun logBodyReq(sb:StringBuilder,request: Request,connection: Connection?) {
        logHeadersReq(sb, request, connection)
        sb.appendLine("RequestBody:${request.body.toString()}")
    }

    private fun logHeadersReq(sb:StringBuilder,request: Request,connection: Connection?) {
        logBasicReq(sb, request, connection)
        val headers:String = request.headers.joinToString(""){
            "请求 Header: {${it.first}=${it.second}}\n"
        }
        sb.appendLine(headers)
    }

    private fun logBasicReq(sb:StringBuilder,request: Request,connection: Connection?){
        sb.appendLine("请求 method:${request.method} url:${decodeUrlStr(request.url.toString())} tag:${request.tag()} protocol:${connection?.protocol()?:Protocol.HTTP_1_1}")
    }

    private fun logResponse(response: Response) {
        val sb = StringBuilder()
        sb.appendLine("\r\n")
        sb.appendLine("<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-")
        when(logLevel) {
            LogLevel.NONE->{}
            LogLevel.BASIC->{
                logBasicRes(sb,response)
            }
            LogLevel.HEADERS->{
                logHeadersRes(sb,response)
            }
            LogLevel.BODY->{
                logHeadersRes(sb,response)
                kotlin.runCatching {
                    val peekBody:ResponseBody = response.peekBody(1024*1024)
                    sb.appendLine(peekBody.string())
                }.getOrNull()
            }
        }
        sb.appendLine("<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-")
        logIt(sb,ColorLevel.INFO)
    }

    private fun logHeadersRes(sb: StringBuilder,response: Response) {
        logBasicRes(sb,response)
        val headers:String = response.headers.joinToString(""){
            "响应 Header: ${it.first}=${it.second}"
        }
        sb.appendLine(headers)
    }

    private fun logBasicRes(sb: StringBuilder,response: Response) {
        sb.appendLine("响应 protocol: ${response.protocol} code: ${response.code} message: ${response.message}")
            .appendLine("响应 request URL: ${decodeUrlStr(response.request.url.toString())}")
            .appendLine("响应 sentRequestTime: ${toDateTimeStr(response.sentRequestAtMillis,MILLIS_PATTERN)} receivedResponseTime: ${toDateTimeStr(response.receivedResponseAtMillis,MILLIS_PATTERN)}")
    }


    /**
     * url解码
     */
    private fun decodeUrlStr(url:String):String? {
        return kotlin.runCatching {
            URLDecoder.decode(url,"utf-8")
        }.onFailure { it.printStackTrace() }
            .getOrNull()
    }

    private fun logIt(any:Any,tempLevel:ColorLevel?=null) {
        when(tempLevel?:colorLevel) {
            ColorLevel.VERBOSE-> Log.v(logTag,any.toString())
            ColorLevel.DEBUG->Log.d(logTag,any.toString())
            ColorLevel.INFO->Log.i(logTag,any.toString())
            ColorLevel.WARN->Log.w(logTag,any.toString())
            ColorLevel.ERROR->Log.e(logTag,any.toString())
        }
    }

    companion object {
        private const val TAG="<KtHttp>"
        const val MILLIS_PATTERN = "yyyy-MM-dd HH:mm:ss.SSSXXX"

        fun toDateTimeStr(millis:Long, pattern:String):String {
            return SimpleDateFormat(pattern, Locale.getDefault()).format(millis)
        }
    }


    enum class LogLevel {
        NONE,  //不打印
        BASIC, //只打印首行，请求/响应
        HEADERS, //打印请求和响应的所有header
        BODY    //全部打印
    }

    enum class ColorLevel {
        VERBOSE,
        DEBUG,
        INFO,
        WARN,
        ERROR
    }
}